﻿using System;
using System.Linq;
using System.Reflection;
using DepIC.Entities;

namespace DepIC.Helpers
{
    internal static class PropertyInjector
    {
        public static void Inject(IReadOnlyContainer container, Instance instance)
        {
            Checker.ArgumentIsNull(container, "container");
            Checker.ArgumentIsNull(instance, "instance");

            var type = instance.Type;

            var propertiesWithInjectAttr = InjectAttributeHelper.GetProperties(type);

            CheckTypesOfPropertiesAreRegistered(container, type, propertiesWithInjectAttr);

            foreach (var propertyInfo in propertiesWithInjectAttr)
            {
                var instanceOfPropertyType = container.Get(propertyInfo.PropertyType);
                propertyInfo.SetValue(instance.Object, instanceOfPropertyType, null);
            }
        }

        private static void CheckTypesOfPropertiesAreRegistered(IReadOnlyContainer container, Type type, PropertyInfo[] properties)
        {
            Checker.ArgumentIsNull(container, "container");
            Checker.ArgumentIsNull(type, "type");
            Checker.ArgumentIsNull(properties, "properties");

            var typesOfProperties =
                properties
                    .Select(p => p.PropertyType)
                    .ToArray();

            var unknownPropertyTypes =
                typesOfProperties
                    .Where(t => !container.Contains(t))
                    .ToArray();

            if (unknownPropertyTypes.Any())
            {
                var stringOfTypes = string.Join(",", unknownPropertyTypes.Select(t => t.ToString()));
                throw new ContainerException(
                    "The property types ({0}) of type '{2}' are not registered in the container.",
                    stringOfTypes, type);
            }
        }
    }
}
